package com.share.tools;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author caifan
 * @date 2019/10/20
 */
public class FileUtils {
    private final static Logger logger =  LoggerFactory.getLogger(FileUtils.class);
    private static AtomicInteger integer = new AtomicInteger();
    private static byte[] buf = new byte[1024];

    /**
     * 分割文件
     *
     * @param dir      目录
     * @param fileName 文件名
     * @throws Exception
     */
    public static void fileSplit(String dir, String fileName) throws Exception {
        try (FileInputStream inputStream = new FileInputStream(dir + File.separator + fileName)) {
            FileChannel channel = inputStream.getChannel();
            long filesize = 0;
            long buf = 1024 * 10000;
            while (filesize < channel.size()) {
                File file = new File(dir + integer.getAndIncrement() + ".ctc");
                FileOutputStream os = new FileOutputStream(file);
                FileChannel osChannel = os.getChannel();
                channel.transferTo(filesize, buf, osChannel);
                filesize = filesize + buf;
            }
        }
    }

    /**
     * 文件合并
     *
     * @param dir
     * @param fileName
     * @throws Exception
     */
    public static void filemerge(String dir, String fileName) throws Exception {
        File file = new File(dir);
        File[] files = file.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                if (name.endsWith(".ctc")) {
                    return true;
                }
                return false;
            }
        });
        File fileMerge = new File(dir + File.separator + fileName);
        if (!fileMerge.exists()) {
            fileMerge.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(fileMerge);
        FileChannel fosChannel = fos.getChannel();
        long buf = 1024 * 10000;
        for (int j = 0; j < files.length; j++) {
            FileInputStream fis = new FileInputStream("D:/filetest/chrome/" + j + ".ctc");
            FileChannel channel = fis.getChannel();
            fosChannel.transferFrom(channel, fosChannel.size(), buf);
        }
    }

    /**
     * 压缩文件夹及文件
     *
     * @param zipFilePath 压缩文件目录
     * @param fileName    压缩的文件名
     */
    public static void zipDir(String zipFilePath, String fileName) {
        try (FileOutputStream fos = new FileOutputStream(fileName); ZipOutputStream zos = new ZipOutputStream(fos)) {
            Files.walkFileTree(Paths.get(zipFilePath), new FileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                    Objects.requireNonNull(dir);
                    Objects.requireNonNull(attrs);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    // 压缩使用相对路径，getParent会把根路径压缩进来
                    zos.putNextEntry(new ZipEntry(Paths.get(zipFilePath).relativize(file.getParent()) + File.separator + file.toFile().getName()));

                    FileInputStream fis = new FileInputStream(file.toFile());
                    int len;
                    while ((len = fis.read(buf)) != -1) {
                        zos.write(buf, 0, len);
                    }
                    fis.close();
                    zos.closeEntry();
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    Objects.requireNonNull(file);
                    throw exc;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            logger.error("zip file error:", e);
            e.printStackTrace();
        }
    }

    /**
     * 压缩流
     *
     * @param isMap    流与路径映射关系
     * @param fileName 文件名
     */
    public static void zipInputStream(Map<String, InputStream> isMap, String fileName) {
        try (FileOutputStream fos = new FileOutputStream(fileName);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            for (Map.Entry<String, InputStream> map : isMap.entrySet()) {
                zos.putNextEntry(new ZipEntry(map.getKey()));
                InputStream is = map.getValue();
                int len;
                while ((len = is.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
                is.close();
                zos.closeEntry();
            }
        } catch (IOException e) {
            logger.error("zip file error:", e);
            e.printStackTrace();
        }
    }

    /**
     * 删除目录
     *
     * @param dir 目录
     * @throws IOException 异常
     */
    public static void deleteDir(String dir) throws IOException {
        if (!Files.exists(Paths.get(dir))) {
            return;
        }
        Files.walkFileTree(Paths.get(dir), new FileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                Stream<Path> pathStream = Files.list(dir);
                pathStream.forEach(path -> {
                    try {
                        if (Files.isDirectory(path) && Files.list(path).count() == 0) {
                            Files.deleteIfExists(path);
                        }
                    } catch (Exception e) {
                        logger.error("delete dir:{}", e.getMessage());
                        e.printStackTrace();
                    }
                });
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
                if (Files.exists(path) && !Files.isDirectory(path)) {
                    Files.deleteIfExists(Paths.get(path.getParent() + File.separator + path.getFileName()));
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                if (Files.list(dir).count() == 0) {
                    File file = new File(dir.toString());
                    file.deleteOnExit();
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }
}
